var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');

var routes = require('./routes/index');
var users = require('./routes/users');

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'hbs');

// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', routes);
app.use('/users', users);

// catch 404 and forward to error handler
app.use(function (req, res, next) {
    var err = new Error('Not Found');
    err.status = 404;
    next(err);
});

// error handlers

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
    app.use(function (err, req, res, next) {
        res.status(err.status || 500);
        res.render('error', {
            message: err.message,
            error: err
        });
    });
}

// production error handler
// no stacktraces leaked to user
app.use(function (err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
        message: err.message,
        error: {}
    });
});

module.exports = app;

// Setup basic express server
var server = require('http').createServer(app);
var SocketIO = require('socket.io');
var io = new SocketIO(server, {});
var port = process.env.PORT || 3000;

server.listen(port, function () {
    console.log('Server listening at port %d', port);
});

// Chat room
var numUsers = 0;
var SocketMgr = require('./SocketMgr');
var socketMgr = new SocketMgr();
var ChatMessage = require('./ChatMessage');
var cm = new ChatMessage(io.sockets.sockets);
var uuid = require('node-uuid');

/**
 * data{fromChatId,toChatId,type,content,status,time}
 */
io.on('connection', function (socket) {

    var addedUser = false;

    console.log(socket.id);

    // when the client emits 'add user', this listens and executes
    socket.on('register', function (data) {
        if (addedUser) return;

        console.log(data);
        socketMgr.put(data.user.uuid, socket.id);

        // we store the username in the socket session for this client
        ++numUsers;
        addedUser = true;

        socketMgr.emit(io.sockets.sockets, data.user.uuid, 'register', socket.fromChatId + "connected");
    });

    // when the client emits 'new message', this listens and executes
    socket.on('message', function (data) {

        console.log(data);

        cm.insert({
            uuid: uuid.v4(),
            fromUser: data.fromUser,
            toUser: data.toUser,
            type: data.type,
            content: data.content,
            status: 0,
            time: new Date().getTime()
        }, function (result) {
            socketMgr.emit(io.sockets.sockets, data.toUser.uuid, "message", result);
            console.log(result);
        });
    });

    socket.on('received', function (data) {
        cm.updateStatus(io.sockets.sockets, data.toUser.uuid, 1);
    });

    /**
     * {chatId,message}
     */
    // when the client emits 'typing', we broadcast it to others
    socket.on('typing', function (data) {
        socketMgr.emit(io.sockets.sockets, data.toUser.uuid, "typing", data);
    });

    /**
     * {chatId,message}
     */
    // when the client emits 'stop typing', we broadcast it to others
    socket.on('typed', function (data) {
        socketMgr.emit(data.toUser.uuid, "typed", data);
    });

    /**
     * {chatId,message}
     */
    // when the user disconnects.. perform this
    socket.on('disconnect', function (data) {
        if (addedUser) {
            --numUsers;

            // echo globally that this client has left
            socketMgr.emit(data.toUser.uuid, "disconnect", data);
        }
    });
});